#include "StdAfx.h"
#include "Parser.h"


static BOOL IsWhiteSpace(CHAR ch);


VOID CParser::SkipWhiteSpacesAndNewLines(BOOL bExpectEof)
{
	while (nCursor < nLength)
	{
		if (m_rScript[nCursor++] > 0x20)
		{
			return;
		}
	}
	throw bExpectEof;
}

VOID CParser::SkipWhiteSpaces()
{
	while (nCursor < nLength)
	{
		CHAR ch = m_rScript[nCursor++];
		if (!IsWhiteSpace(ch))
		{
			return;
		}
	}
	throw FALSE;
}

VOID CParser::SkipAtLeastOneWhiteSpace()
{
	if (nCursor >= nLength)
	{
		throw FALSE;
	}

	if (!IsWhiteSpace(m_rScript[nCursor++]))
	{
		throw FALSE;
	}

	while (nCursor < nLength)
	{
		if (!IsWhiteSpace(m_rScript[nCursor]))
		{
			return;
		}
	}
	throw FALSE;
}

VOID CParser::SkipAtLeastOneNewLine()
{
	if (nCursor >= nLength)
	{
		throw FALSE;
	}

	CHAR ch = m_rScript[nCursor++];
	if ((ch != '\n') && (ch != '\r'))
	{
		throw FALSE;
	}

	SkipWhiteSpacesAndNewLines(TRUE);
}


BOOL CParser::NextIsAlpha()
{
	CHAR ch = m_rScript[nCursor];
	return ((ch >= 'A') && (ch <= 'Z')) ||
		((ch >= 'a') && (ch <= 'z')) ||
		(ch == '_');
}

BOOL CParser::NextIsAlphanum()
{
	CHAR ch = m_rScript[nCursor];
	return ((ch >= 'A') && (ch <= 'Z')) ||
		((ch >= 'a') && (ch <= 'z')) ||
		((ch >= '0') && (ch <= '9')) ||
		(ch == '_');
}


LONG CParser::ReadNumber()
{
	CHAR ch = m_rScript[nCursor++];
	if ((ch < '0') || (ch > '9'))
	{
		throw FALSE;
	}
	LONG lResult = ch - '0';

	while (nCursor < nLength)
	{
		ch = m_rScript[nCursor];
		if ((ch < '0') || (ch > '9'))
		{
			break;
		}

		lResult = lResult * 10 + (ch - '0');
		nCursor++;
	}

	return lResult;
}

CStringA CParser::ReadIdentifier()
{
	if (!NextIsAlpha())
	{
		throw FALSE;
	}

	CStringA strResult;
	strResult = m_rScript[nCursor++];

	while (nCursor < nLength)
	{
		if (!NextIsAlphanum())
		{
			break;
		}
		strResult += m_rScript[nCursor++];
	}

	return strResult;
}

CStringA CParser::ReadString()
{
	CheckNext("\"");
	CStringA strResult;
	while (nCursor < nLength)
	{
		CHAR ch = m_rScript[nCursor++];
		if (ch == '\"')
		{
			return strResult;
		}
		strResult += ch;
	}
	throw FALSE;
}


CParser::CParser(CStringA &a_rScript) :
m_rScript(a_rScript)
{
}


VOID CParser::Parse()
{
}


BOOL CParser::NextIs(LPCSTR pszCompare)
{
	CStringA strCompare = pszCompare;

	UINT nCompareLength = strCompare.GetLength();
	if (nLength - nCursor < nCompareLength)
	{
		return FALSE;
	}

	for (UINT nTempCursor = 0; nTempCursor < nCompareLength; nTempCursor++)
	{
		if (m_rScript[nCursor + nTempCursor] != strCompare[nTempCursor])
		{
			return FALSE;
		}
	}

	nCursor += nCompareLength;
	return TRUE;
}

VOID CParser::CheckNext(LPCSTR pszCheck)
{
	if (!NextIs(pszCheck))
	{
		throw FALSE;
	}
}


VOID CParser::ParseDefine()
{
	SkipAtLeastOneWhiteSpace();

	CStringA strIdentifier = ReadIdentifier();
	if (m_mapMacros.count(strIdentifier) != 0)
	{
		throw FALSE;
	}

	SkipAtLeastOneWhiteSpace();

	CStringA strExpansion;

	BOOL bSlash = FALSE;
	while (nCursor < nLength)
	{
		CHAR ch = m_rScript[nCursor++];

		if (ch == '\\')
		{
			strExpansion += ch;
			bSlash = TRUE;
			continue;
		}

		if (((ch == '\n') || (ch == '\r')) && !bSlash)
		{
			break;
		}

		strExpansion += ch;
		bSlash = FALSE;
	}

	SkipWhiteSpacesAndNewLines(TRUE);

	m_mapMacros[strIdentifier] = strExpansion;
}


BOOL IsWhiteSpace(CHAR ch)
{
	return (ch <= 0x20) && (ch != '\n') && (ch != '\r');
}
